﻿Option Strict On
Option Explicit On
Option Infer On

Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Xml.Linq
Imports GenDotNet.Task.Common
Imports GenDotNet.ObjectModel
Imports <xmlns:orm="http://kadgen.com/KADORM.xsd">
Imports <xmlns:kd="http://kadgen.com/Special.xsd">

Namespace GenInputMetadata
   Public Class ObjectData
      Inherits BaseData
      Implements IObjectData

      'Private Shared mIsDataLoaded As Boolean
      Private mProperties As List(Of IPropertyData)
      Private mChildren As List(Of IChildData)
      Private mCriteria As List(Of ICriteriaData)
      Private mStoredProcs As Dictionary(Of StoredProcedureCategory, IStoredProcedureData)
      Private mExtraProperties As List(Of IPropertyData)
      Private mForeignKeys As List(Of IForeignKeyData)
      Private mPrivileges As List(Of IClassPrivilegeData)

      'Public Shared Function Load(ByVal xElement As XElement) As ObjectData
      '   'If Not mIsDataLoaded Then
      '   '   LoadData(xElement)
      '   '   mIsDataLoaded = True
      '   'End If
      '   Return RootData.GetObject(xElement.@Name)
      'End Function

      Friend Shared Function Load( _
               ByVal rootData As RootData, _
               ByVal element As XElement) _
               As ObjectData
         Dim ret = New ObjectData(rootData, element)
         ret.mProperties = PropertyData.Load(ret, From x In Element...<orm:Property>)
         ret.mChildren = ChildData.Load(ret, From x In Element.<orm:ChildCollections>.<orm:ChildCollection>)
         ret.mCriteria = CriteriaData.Load(ret, From x In Element...<orm:FilterCriteria> Where Not x.@IsPrimaryKey.IsTrue())
         ret.mForeignKeys = ForeignKeyData.Load(ret, From x In Element...<orm:ForeignKeyTable> Where Not x.@IsPrimaryKey.IsTrue())
         ret.mPrivileges = ClassPrivilegeData.Load(ret, From x In Element...<orm:ClassPrivilege> Where Not x.@IsPrimaryKey.IsTrue())
         ret.mExtraProperties = PropertyData.Load(ret, From x In Element...<orm:ForeignKeyTables>...<orm:Property>)
         ret.mStoredProcs = New Dictionary(Of StoredProcedureCategory, IStoredProcedureData)
         ret.mStoredProcs.Add(StoredProcedureCategory.Create, StoredProcedureData.Load(ret, Element.<orm:CreateSP>.FirstOrDefault))
         ret.mStoredProcs.Add(StoredProcedureCategory.Retrieve, StoredProcedureData.Load(ret, Element.<orm:RetrieveSP>.FirstOrDefault))
         ret.mStoredProcs.Add(StoredProcedureCategory.Update, StoredProcedureData.Load(ret, Element.<orm:UpdateSP>.FirstOrDefault))
         ret.mStoredProcs.Add(StoredProcedureCategory.Delete, StoredProcedureData.Load(ret, Element.<orm:DeleteSP>.FirstOrDefault))
         ret.mStoredProcs.Add(StoredProcedureCategory.SetSelect, StoredProcedureData.Load(ret, Element.<orm:SetSelectSP>.FirstOrDefault))
         Return ret
      End Function

      Private Sub New(ByVal rootData As RootData, _
                     ByVal element As XElement)
         MyBase.New(rootData, element)
      End Sub

#Region "IObject Data Implementation"
      Public ReadOnly Property ClassName() _
               As String _
               Implements IObjectData.ClassName
         Get
            Return Element.@Name
         End Get
      End Property

      Public ReadOnly Property PrimaryKey() _
               As IPropertyData _
               Implements IObjectData.PrimaryKey
         Get
            Dim pkeys = PrimaryKeys
            If pkeys.Count = 0 Then
               Throw New InvalidOperationException("No primary key defined")
            ElseIf pkeys.Count > 1 Then
               Throw New InvalidOperationException("Multi-column primary key not supported by this method")
            Else
               Return pkeys.Single
            End If
         End Get
      End Property

      Public ReadOnly Property PrimaryKeys() _
               As List(Of IPropertyData) _
               Implements IObjectData.PrimaryKeys
         Get
            Dim originalName = Me.OriginalName
            Return (From prop In Properties _
                    Where prop.IsPrimaryKey() And prop.TableName = originalName).ToList()
         End Get
      End Property

      Public ReadOnly Property Caption() _
               As String _
               Implements IObjectData.Caption
         Get
            Return Element.@Caption
         End Get
      End Property

      Public ReadOnly Property IsLookup() _
               As Boolean _
               Implements IObjectData.IsLookup
         Get
            Return Element.@IsLookup.IsTrue()
         End Get
      End Property

      Public ReadOnly Property OriginalName() _
               As String _
               Implements IObjectData.OriginalName
         Get
            Return Element.@OriginalName
         End Get
      End Property

      Public ReadOnly Property Children() _
               As System.Collections.Generic.List(Of IChildData) _
               Implements IObjectData.Children
         Get
            Return mChildren
         End Get
      End Property

      Public ReadOnly Property LocalizedProperties() _
               As System.Collections.Generic.List(Of IPropertyData) _
               Implements IObjectData.LocalizedProperties
         Get
            Return (From prop In Properties Where prop.IsLocalizedProperty).ToList()
         End Get
      End Property

      Public ReadOnly Property Properties() _
               As System.Collections.Generic.List(Of IPropertyData) _
               Implements IObjectData.Properties
         Get
            Return mProperties
         End Get
      End Property

      Public ReadOnly Property DescriptionProperties() _
                  As System.Collections.Generic.List(Of IPropertyData) _
                  Implements IObjectData.DescriptionProperties
         Get
            Dim description = From prop In Properties _
                              Where prop.UseForDesc And Not prop.IsPrimaryKey
            Dim stringProperties = From prop In Properties _
                                   Where prop.NetType = StandardNetType.String
            Dim allProperties = From prop In Properties
            Dim q = If(description.Count > 0, description, If(stringProperties.Count > 0, stringProperties, allProperties))
            Return q.ToList()
         End Get
      End Property

      Public ReadOnly Property AlternateKeyCriteria() _
               As System.Collections.Generic.List(Of ICriteriaData) _
               Implements IObjectData.AlternateKeyCriteria
         Get
            Return mCriteria
         End Get
      End Property

      Public ReadOnly Property AlternateKeySetCriteria() _
               As System.Collections.Generic.List(Of ICriteriaData) _
               Implements IObjectData.AlternateKeySetCriteria
         Get
            Return CriteriaData.Load(Me, From x In Element.<orm:SetFilterCriteria>)
         End Get
      End Property

      Public ReadOnly Property CanListAll() _
               As Boolean _
               Implements IObjectData.CanListAll
         Get
            Return Element.@kd:AllowListAll.IsTrue
         End Get
      End Property

      Public ReadOnly Property CollectionClassName() _
               As String _
               Implements IObjectData.CollectionClassName
         Get
            Return ClassName & "Collection"
         End Get
      End Property

      Public ReadOnly Property ReadOnlyListClassName() _
               As String _
               Implements IObjectData.ReadonlyListClassName
         Get
            Return ClassName & "List"
         End Get
      End Property

      Public ReadOnly Property ReadOnlyClassName() _
                As String _
                Implements IObjectData.ReadonlyClassName
         Get
            Return ClassName & "Info"
         End Get
      End Property

      Public ReadOnly Property ConnectionStringName() _
               As String _
               Implements IObjectData.ConnectionStringName
         Get
            Dim xDoc = Me.Element.Document
            Return (From root In xDoc...<orm:MappingRoot> Select root.@MapDataStructure).First
         End Get
      End Property

      Public ReadOnly Property StoredProcedure( _
               ByVal category As StoredProcedureCategory) _
               As IStoredProcedureData _
               Implements IObjectData.StoredProcedure
         Get
            Dim ret As IStoredProcedureData = Nothing
            mStoredProcs.TryGetValue(category, ret)
            Return ret
         End Get
      End Property

      Public ReadOnly Property ExtraProperties() _
               As System.Collections.Generic.List(Of IPropertyData) _
               Implements IObjectData.ExtraProperties
         Get
            Return mExtraProperties
         End Get
      End Property

      Public ReadOnly Property ClassNamespace() _
               As String _
               Implements IObjectData.ClassNamespace
         Get
            Return Element.Document.Root.@Namespace
         End Get
      End Property

      Public ReadOnly Property Id() As System.Guid Implements IObjectData.Id
         Get
            ' TODO: Brind a guid unique to the entity forward
            Return Guid.NewGuid()
         End Get
      End Property

      Public ReadOnly Property ForeignKeys() As System.Collections.Generic.List(Of IForeignKeyData) Implements IObjectData.ForeignKeys
         Get
            Return Me.mForeignKeys
         End Get
      End Property

      Public ReadOnly Property Privileges() As System.Collections.Generic.List(Of IClassPrivilegeData) Implements IObjectData.Privileges
         Get
            Return (Me.mPrivileges)
         End Get
      End Property
#End Region

   End Class
End Namespace
